#ifndef THREAD_POOL
#define THREAD_POOL

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <mutex>
#include <condition_variable>

class ThreadPool
{
private:
	boost::asio::io_service io_service_;
	boost::asio::io_service::work work_;
	boost::thread_group threads_;
	std::size_t running_;
	std::mutex mutex_;
	std::condition_variable cv_;
public:

	ThreadPool(std::size_t pool_size) :
			work_(io_service_), running_(0)
	{
		for (std::size_t i = 0; i < pool_size; ++i)
		{
			threads_.create_thread(
					boost::bind(&boost::asio::io_service::run, &io_service_));
		}
	}

	~ThreadPool()
	{
		io_service_.stop();

		try
		{
			threads_.join_all();
		} catch (...)
		{
		}
	}

	template<typename Task>
	void run_task(Task task)
	{
		std::lock_guard<std::mutex> lock(mutex_);
		++running_;

		io_service_.post(boost::bind( &ThreadPool::wrap_task, this,
                boost::function< void() >( task ) ) );
	}

	void wait()
	{
		std::unique_lock<std::mutex> lock(mutex_);
		cv_.wait(lock, [this]{return running_ == 0;});
	}

private:
	  void wrap_task( boost::function< void() > task )
	  {
			try
			{
				task();
			}
			catch (...)
			{
			}

			std::lock_guard<std::mutex> lock(mutex_);
			if (--running_ == 0)
			{
				cv_.notify_all();
			}
	  }
};
#endif /*THREAD_POOL*/
